#!/bin/bash

test -z "$CC" && CC=gcc
test -z "$LD" && LD="$CC"

# Do not set this flag to anything. It is being set by the different passes
CFLAGS=

trap : SIGABRT

failed_tests=

# Run a test
function runtest() {
  ./the-test > test.out 2>&1
  if [ $? -ne 0 ] ; then
    echo "*** Fail! ***"
    failed_tests="$failed_tests $1 [$MORE_CFLAGS]"
  else
    echo "Ok."
  fi
}

# Build the new test
function build() {
  rm -f the-test
  rm -f /tmp/test.o
  rm -f /tmp/image.simics

  $CC -c $* $CFLAGS $MORE_CFLAGS -W -Wall -o /tmp/test.o -DSTACK_SIZE=1024
  $LD /tmp/test.o asm-support.o -o the-test
}

# Test a file
function test_file() {
  echo -n "$1: "
  if [ "$CFLAGS" != "" ] && [ "`grep 'optimization level' $1 | grep -e \"$CFLAGS\"`" != "" ] ; then
    echo "Skipped."
  else
    old_CFLAGS="$CFLAGS"
    if grep 'fno-omit-frame-pointer' $1 > /dev/null 2>&1; then
      CFLAGS="$CFLAGS -fno-omit-frame-pointer"
    fi
    build $*
    CFLAGS="$old_CFLAGS"
    if [ -f the-test ] ; then
      runtest $1
      return
    else
      echo "Compile error [$MORE_CFLAGS]"
    fi
  fi
}

function run_all_tests() {
  if [ "$CFLAGS" == "" ] ; then
    echo -e "\nTesting without optimization"
  else
    echo -e "\nTesting with $CFLAGS"
  fi

  # Testing only some files or all of them?
  if [ "$1" != "" ] ; then
    for file in $*; do
      test_file $file
    done
  else
    for file in test_*.c; do
      test_file $file;
    done
  fi
}

function check_medium() {
  echo -n "medium-test.c: "
  failed=
  build medium-test.c
  if [ -f the-test ] ; then
    rm -rf symtab.txt
    objdump -t the-test | egrep "the_struct|big_ar" > symtab.txt
    while read ofs scope type section length name; do
	length=$((0x`echo $length | sed -e 's/^0*//'`))
	if test $length -gt 65536; then
	  case $section in
	    .lbss | .ldata ) ;;
	    * ) failed=yes
          	echo -en "\n    Bad section: $name: $section $length"
		;;
	  esac
	fi
    done < symtab.txt
    rm -rf symtab.txt
    if test -z "$failed"; then
      runtest medium-test.c
    else
      echo -e "\n    Fail! [$MORE_CFLAGS]"
      failed_tests="${failed_tests}medium-test.c[$MORE_CFLAGS]\n"
    fi
  else
    echo "Compile error [$MORE_CFLAGS]"
  fi
}

function medium_test() {
  echo -e "\nTesting medium model"
  old_CFLAGS="$CFLAGS"
  CFLAGS="$CFLAGS -mcmodel=medium"
  for T in int; do
    # for S in '1' '1000' '65534' '1024*1024ll' '1024*1024*256ll' '1024*1024*1024ll'; do
    for S in '65534' '65537' ; do
      for NUM_A in 3 4; do
        for NUM_S in 0 4; do
	  for STATIC in "" static; do
	    for INIT in "" '={1}'; do
	      for PIC in "" "-fPIC"; do
	        MORE_CFLAGS="$PIC -DT=$T -DSIZE=$S -DNUM_ARRAY=${NUM_A} -DNUM_STRUCT=${NUM_S} -DSTATIC=$STATIC -DINIT=$INIT"
		check_medium
	      done
	    done
	  done
	done
      done
    done
  done
  CFLAGS="$old_CFLAGS"
}

do_medium=
for arg in $*; do
  case $arg in
    -m) do_medium=yes; shift;;
  esac
done

echo "Running make to build all autogenerated tests"
make

run_all_tests $*
test -n "$do_medium" && medium_test

CFLAGS=-O1
run_all_tests $*
test -n "$do_medium" && medium_test

CFLAGS=-O2
run_all_tests $*
test -n "$do_medium" && medium_test

if test -n "$failed_tests"; then
  echo -e "failed: $failed_tests"
  exit 1
fi
exit 0
